package com.itcoon.transform.starter.handler;

import com.itcoon.transform.base.exception.TransformException;
import com.itcoon.transform.base.TransformHandlerComposite;
import com.itcoon.transform.base.definition.InjectDefinition;
import com.itcoon.transform.base.definition.ModelDefinition;
import com.itcoon.transform.base.pool.AssembleBeanHolder;
import com.itcoon.transform.base.register.unannotated.UnAnnotatedAssembleModelRegisterComposite;
import com.itcoon.transform.base.utils.TransformServiceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class TransformHandlerCompositeImpl implements TransformHandlerComposite {
    private static final Logger log = LoggerFactory.getLogger(TransformHandlerCompositeImpl.class);

    private static  final AssembleBeanHolder BEAN_HOLDER = AssembleBeanHolder.getInstance();
    @Autowired
    private List<TransformHandler> transformHandlers;

    @Autowired
    public UnAnnotatedAssembleModelRegisterComposite assembleModelRegisterComposite;

    @Override
    public <T, R> R handle(Class<R> targetClass, T source, List<InjectDefinition.InjectInfo> injectInfos) {
        if(source == null){
            return null;
        }
        ModelDefinition md = BEAN_HOLDER.getModelDefinition(targetClass, source);
        if(md ==null){
            assembleModelRegisterComposite.register(targetClass, TransformServiceUtils.getOriginClass(source));
            md = BEAN_HOLDER.getModelDefinition(targetClass, source);
        }
        if(!md.getOriginClass().isAssignableFrom(source.getClass())){
            throw new TransformException(String.format("[Transform4j] - Error Source Type, required source is {}, but not found", md.getOriginClass().getName()));
        }
        for (TransformHandler transformHandler : transformHandlers) {
            if (transformHandler.supports(targetClass)) {
                try {
                    return transformHandler.handle(targetClass, source, injectInfos);
                }catch(Exception e){
                    log.error("[Transform4j] - can not assemble instance of class named #{} from #{}, reason is:  {}", targetClass.getName(), source, e.getMessage());
                    log.error(e.getMessage(), e);
                    throw new TransformException("Transform4j Exception: " + e.getMessage());
                }
            }
        }
        throw new TransformException("Transform4j Exception:  can not found transform handler to transform, targetClass#" + targetClass.getName());
    }
}
